
import Vuex from 'vuex'


/**
 * 定义计算属性 keyName ，表示 state 在 localStorage 中的键名 ，当访问 keyName 时，如果 keyName 不存在，则会取默认值 'StoreState'
 */
Object.defineProperty(Vuex.Store.prototype, 'keyName', {
  get: function () {
    if (!this._keyName) {
      this._keyName = 'StoreState';
    }

    return this._keyName;
  },
  set: function (newValue) {
    if (newValue) {
      this._keyName = newValue;
    }
  }
})







/**
 * 将 state 存储在 localStorage 中；
 * @param keyName ? : string  存储在 localStorage 中的键名，如果未设置该参数，则自动次用 store.keyName 的值作为键名
 */
Vuex.Store.prototype.saveState = function (keyName) {
  this.keyName = keyName;
  localStorage.setAnyItem(this.keyName, this.state);
}




/**
 * 获取存储在 localStorage 中的 state 对象
 * @returns state
 */
Vuex.Store.prototype.getLocalState = function () {
  return localStorage.getParsedItem(this.keyName);
}







/**
 * 把 store 的配置数组中所有的配置对象合并成一个store配置对象
 * @param storeConfigs : Array<StoreOptions>  store 的配置数组
 * @returns StoreOptions    store选项对象
 */
function mergeStoreConfigs(storeConfigs){

  let storeOptions = storeConfigs.reduce(function(merged, config){

    Object.keys(config).forEach(function(key){
      let configPropValue = config[key];
      let mergedPropValue = merged[key];
      let newPropValue = null;

      // 注意：有些case有 break，有些没有；这样写可能不太好理解，但比用 if else 节省了好几行代码，从而提高了性能
      switch (key){
        case "plugins":{
          newPropValue = [...mergedPropValue,...configPropValue];
          break;
        }
        case "state":{
          if (typeof configPropValue == "function"){
            configPropValue = configPropValue();
          }
          // 注意：此处没有 break ;
        }
        default:{
          newPropValue = {...mergedPropValue,...configPropValue}
        }

      }

      merged[key] = newPropValue;

    });


    return merged;

  }, {});


  return storeOptions;

}







/**
 * 用初始 state 配置 store的选项对象
 * @param storeOptions : StoreOptions   store的选项对象
 * @param initState : State    初始state
 * @returns StoreOptions    返回带有初始 state 的选项对象
 *
 *
 * 说明：
 * 由于模块 modules 中的 state 会覆盖全局的 state ，所以，通过把初始 state 传给全局的 state 的方式不能达到给模块设置初始值的目的；
 * 此方法就是为解决这个问题而来的；
 */
function configStoreOptionsWhitInitState(storeOptions,initState) {
  let modules = storeOptions.modules;

  if (initState){

    if (modules){

      Object.keys(modules).forEach(function (key) {

        let subStoreOptions = modules[key];
        let subInitState = initState[key];

        subStoreOptions = configStoreOptionsWhitInitState(subStoreOptions,subInitState);


        modules[key] = subStoreOptions;

        try{
          delete initState[key];
        }catch (e) {

        }

      });

      storeOptions.modules = modules;

    }


    storeOptions.state = initState;

  }



  return storeOptions;
}





// 给 Vuex.Store 添加 mergeStoreConfigs 方法
Vuex.Store.mergeStoreConfigs = mergeStoreConfigs;

// 给 Vuex.Store 添加 configStoreOptionsWhitInitState 方法
Vuex.Store.configStoreOptionsWhitInitState = configStoreOptionsWhitInitState;








/**
 * 把 store 配置数组中所有的配置对象合并成一个带有初始 statestore配置对象
 * @param storeConfigs : Array<StoreOptions>  store 的配置数组
 * @param initState : State    初始state
 * @returns StoreOptions    返回带有初始 state 的选项对象
 */
Vuex.Store.mergeStoreConfigsWhitInitState = function (storeConfigs,initState) {
  let storeOptions = this.mergeStoreConfigs(storeConfigs);
  storeOptions = this.configStoreOptionsWhitInitState(storeOptions,initState);
  return storeOptions;
};


